package com.katesoft.scale4j.rttp.jobs;

import com.katesoft.scale4j.common.services.IBeanNameReferences;
import com.katesoft.scale4j.log.Logger;
import com.katesoft.scale4j.log.LogFactory;
import org.apache.commons.lang.ArrayUtils;
import org.perf4j.StopWatch;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SchedulerAccessor;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.Arrays;
import java.util.Collection;

import static com.katesoft.scale4j.common.services.IBeanNameReferences.DATASOURCE_TRANSACTION_MANAGER;

/**
 * This class allows to register and schedule jobs(triggers) as well as listeners within Quartz job scheduler.
 * <p/>
 * You can set autoDetectJobs flag to true and do not enumerate jobs/triggers or pass collection of triggers/jobDetails that need to be registered(if
 * autoDetect
 * is not acceptable behaviour).
 *
 * @author kate2007
 */
public class SchedulerJobsRegistrator extends SchedulerAccessor implements ApplicationContextAware, InitializingBean
{
    private Logger logger = LogFactory.getLogger(getClass());
    private ApplicationContext applicationContext;
    private boolean autoDetectJobs = true;

    /**
     * this class is able to autoDetect trigger that are defined in ApplicationContext and this feature is enabled by default.
     * <p/>
     * This may not be acceptable behaviour for some application that would like to enumerate all trigger manually and skip some at all. In this case set
     * autoDetectJobs to false and inject triggers and jobDetails(if necessary) manually.
     *
     * @param autoDetectJobs derive triggers and job details from ApplicationContext automatically.
     */
    public void setAutoDetectJobs(boolean autoDetectJobs)
    {
        this.autoDetectJobs = autoDetectJobs;
    }

    public boolean isAutoDetectJobs()
    {
        return autoDetectJobs;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        this.applicationContext = applicationContext;
    }

    @Override
    public void setJobDetails(JobDetail[] jobDetails)
    {
        super.setJobDetails(jobDetails);
        if (jobDetails != null && !ArrayUtils.isEmpty(jobDetails)) {
            logger.debug("setting auto_detect=[false], jobDetails %s provided", Arrays.toString(jobDetails));
            setAutoDetectJobs(false);
        }
    }

    @Override
    public void setTriggers(Trigger[] triggers)
    {
        if (triggers != null && !ArrayUtils.isEmpty(triggers)) {
            super.setTriggers(triggers);
            logger.debug("setting auto_detect=[false], triggers %s provided", Arrays.toString(triggers));
            setAutoDetectJobs(false);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception
    {
        setTransactionManager(applicationContext.getBean(DATASOURCE_TRANSACTION_MANAGER, PlatformTransactionManager.class));
        StopWatch stopWatch = new StopWatch("rttp.scheduler.jobs.registration");
        try {
            if (isAutoDetectJobs()) {
                Collection<Trigger> triggers = applicationContext.getBeansOfType(Trigger.class).values();
                super.setTriggers(triggers.toArray(new Trigger[triggers.size()]));
                logger.debug(" %s triggers were auto registered", triggers.size());
                Collection<JobDetail> jobDetails = applicationContext.getBeansOfType(JobDetail.class).values();
                super.setJobDetails(jobDetails.toArray(new JobDetail[jobDetails.size()]));
                logger.debug(" %s jobDetails were auto registered", jobDetails.size());
            }
            registerListeners();
            registerJobsAndTriggers();
        }
        catch (Exception e) {
            logger.error(e);
            throw e;
        }
        finally {
            stopWatch.stop();
            logger.debug("jobs/triggers/listeners were registered in %s milisecs", stopWatch.getElapsedTime());
        }
    }

    @Override
    protected Scheduler getScheduler()
    {
        return (Scheduler) applicationContext.getBean(IBeanNameReferences.RTTP_CLIENT_SCHEDULER);
    }
}
